Skip to content

docs(prd): 0009 — keep the herd alive (persistent agent runtime) - #341

Merged
ralyodio merged 1 commit into
mainfrom
worktree-prd-herdr-runtime
Aug 9, 2026
Merged

docs(prd): 0009 — keep the herd alive (persistent agent runtime)#341
ralyodio merged 1 commit into
mainfrom
worktree-prd-herdr-runtime

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Adds prd/0009-persistent-agent-runtime.md — a PRD for adopting the ideas behind herdr.dev into moshcode, filtered for what actually fits this codebase.

What herdr gets right, and what's worth taking

herdr's core inversion is "a server owns the terminals; every UI is a client of it." Terminals live in a background server, panes carry semantic agent state (idle/working/blocked/done), and the CLI and socket API are one surface so agents drive it the same way people do.

That inversion is the idea. The implementation — a 10MB Rust multiplexer with mouse drag, pane splits, and a plugin marketplace — is not.

The gaps it exposes here

  • openPassthrough ties every session to the terminal that started it. tabs.mjs reaches for tmux but keys the server to the pit's pid (moshcode-${pid}-${stamp}), so tabs are as mortal as the pit.
  • The pit knows an engine is running; it doesn't know whether it's thinking, blocked on a permission prompt, or finished an hour ago.
  • mirror.mjs documents its own blind spot — once an engine takes the terminal, the browser watches a pit that stopped saying anything. pty.mjs was built to fix this and isn't load-bearing yet.

Shape of the proposal

Three independently shippable phases:

  1. The runtime survives you — a stable named tmux server, named sessions, attach/detach/ps/kill. Bulk of the value, zero state detection required.
  2. The runtime knows what agents are doing — semantic state with herdr's one-authority-per-session rule (engine lifecycle hooks first, screen classification only as fallback, never both), and blocked routed into the existing notify()/ask() fan-out.
  3. One surface for humans and agentsmoshcode agent start|prompt|read|send-keys|wait|stop, all --json, all exposed as moshscript verbs; pty.mjs closes the mirror blind spot and ttyd attaches to a real session.

The blocked → notify path is the part herdr structurally can't do: it can colour a pane, moshcode can text you and type the answer back.

Explicit non-goals

No Rust binary or compiler in the install path (pty.mjs already rejected node-pty for exactly this reason). No pane splits, mouse drag, or theme engine. No second plugin system. No Windows. tmux stays a soft dependency with a tested fallback to today's foreground passthrough.

Sanity check

node --test test/prd.test.mjs test/prd-index-cell.test.mjs test/tui-prd-errors.test.mjs — 39 pass, 0 fail. The README index was regenerated with regenerateIndex() rather than hand-edited.

🤖 Generated with Claude Code

…ol surface

Ports the ideas behind herdr.dev into moshcode: a background runtime that
owns the terminals so sessions survive the pit, semantic agent state
(idle/working/blocked/done/unknown) with one status authority per session,
and a single CLI surface both humans and agents drive.

Deliberately does not port herdr's implementation — no Rust binary, no
multiplexer UI, no pane-plugin marketplace. Leans on the tmux that
tabs.mjs already reaches for, keeps pty.mjs's capability-detection
discipline, and routes "blocked" into the existing notify()/ask() fan-out,
which is the part herdr structurally cannot do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

91 finding(s)

HIGH/CRITICAL: 2 | MEDIUM: 41 | LOW: 48

Severity Rule Location
HIGH manifest-typosquat apps/pwa/package.json:19
HIGH js-ssrf-outbound-request apps/pwa/public/sw.js:45
MEDIUM tls-verification-disabled apps/pwa/src/lib/moshpit-gateway.mjs:299
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:61
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:75
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:101
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:265
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:269
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:314
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:499
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:675
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:677
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:736
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:782
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:852
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:955
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1063
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1199
MEDIUM js-unescaped-html-sink apps/pwa/src/routes/moshpit.mjs:1419
MEDIUM js-dynamic-code-execution apps/pwa/test/apikey-mask.test.mjs:129
MEDIUM sql-template-interpolation apps/pwa/test/credits-webhook-event-match.test.mjs:111
MEDIUM sql-template-interpolation apps/pwa/test/credits-webhook-event-match.test.mjs:131
MEDIUM sql-template-interpolation apps/pwa/test/moshpit-terms.test.mjs:192
MEDIUM sql-template-interpolation src/dns.mjs:2439
MEDIUM sql-template-interpolation src/selfupdate.mjs:166
MEDIUM sql-template-interpolation src/selfupdate.mjs:170
MEDIUM sql-template-interpolation src/selfupdate.mjs:208
MEDIUM sql-template-interpolation src/selfupdate.mjs:209
MEDIUM insecure-temp-file test/dns-disable-restore.test.mjs:93
MEDIUM insecure-temp-file test/dns-disable-restore.test.mjs:310
MEDIUM insecure-temp-file test/plugins.test.mjs:152
MEDIUM insecure-temp-file test/pty.test.mjs:28
MEDIUM insecure-temp-file test/pty.test.mjs:31
MEDIUM insecure-temp-file test/pty.test.mjs:40
MEDIUM insecure-temp-file test/pty.test.mjs:42
MEDIUM insecure-temp-file test/pty.test.mjs:47
MEDIUM insecure-temp-file test/pty.test.mjs:48
MEDIUM insecure-temp-file test/pty.test.mjs:49
MEDIUM insecure-temp-file test/tabs.test.mjs:8
MEDIUM insecure-temp-file test/tabs.test.mjs:13
MEDIUM insecure-temp-file test/tabs.test.mjs:14
MEDIUM insecure-temp-file test/tabs.test.mjs:22
MEDIUM insecure-temp-file test/trust.test.mjs:240
LOW secret-generic-credential apps/pwa/test/apikey-bearer-scheme.test.mjs:30
LOW secret-generic-credential apps/pwa/test/apikey-mask.test.mjs:38
LOW secret-generic-credential apps/pwa/test/apikey-reveal.test.mjs:35
LOW secret-generic-credential apps/pwa/test/approvals-context.test.mjs:28
LOW secret-generic-credential apps/pwa/test/approvals-credits.test.mjs:28
LOW secret-generic-credential apps/pwa/test/approvals-notify.test.mjs:26
LOW secret-generic-credential apps/pwa/test/approvals-resolve-race.test.mjs:20

…and 41 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio marked this pull request as ready for review August 9, 2026 15:46
@ralyodio
ralyodio merged commit a947b98 into main Aug 9, 2026
4 checks passed
@ralyodio
ralyodio deleted the worktree-prd-herdr-runtime branch August 9, 2026 15:47
@ralyodio ralyodio mentioned this pull request Aug 9, 2026
ralyodio added a commit that referenced this pull request Aug 9, 2026
Bump to v0.33.0, releasing the herd (#342) — agent sessions that outlive
the terminal that started them — along with the PRD behind it (#341) and
the moshpit pinned-TLS proxy fix (#343), all of which have been sitting on
main unreleased.

Minor rather than patch: #342 adds six commands (herd, ps, attach, kill,
wait, restore) and six moshscript verbs, and changes none of the existing
ones. `moshcode start claude` with no -d behaves exactly as it did.

This release is what makes any of it reachable. install.sh serves the
latest release tarball rather than main, so until a release carries it
every installed machine answers `unknown command "ps"` — and the npm
channel only moves when publish.yml sees a published GitHub release.

No plugin bumps: stocks and crypto are untouched, and neither names a
command that moved.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant